home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Games of Daze
/
Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso
/
x2ftp
/
msdos
/
libs
/
stk110
/
spredsrc.com
/
SPRED.C
next >
Wrap
C/C++ Source or Header
|
1991-02-25
|
16KB
|
467 lines
/**********************************************************************
* spred.c
*
* The sprite editor for the Sprite support system, main module.
**********************************************************************
This file is part of
STK -- The sprite toolkit -- version 1.1
Copyright (C) Jari Karjala 1991
The sprite toolkit (STK) is a FreeWare toolkit for creating high
resolution sprite graphics with PCompatible hardware. This toolkit
is provided as is without any warranty or such thing. See the file
COPYING for further information.
**********************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include <math.h>
#include <graphics.h>
#include "grtypes.h"
#include "gr.h"
#include "mouse.h"
#include "spred.h"
#include "spredio.h"
#include "spredfio.h"
#define TRUE 1
#define FALSE 0
#define FILE_EXTENSION ".smp"
/**********************************************************************
* Temporary map for various transformations
**********************************************************************/
SPRED_MAP temp_map;
/**********************************************************************
* The user supplied width, height of the sprite
**********************************************************************/
int width=0, height=0;
/**********************************************************************
* FATAL ERROR: Close graphics, print error and exit.
**********************************************************************/
void error(char *s,...)
{
char buf[100];
va_list argptr;
va_start(argptr,s);
vsprintf(buf,s,argptr);
va_end(argptr);
closegraph();
fputs(buf, stderr);
exit(10);
}
/**********************************************************************
* Prints explanation for the error code returned by the sprite file IO
* Return: the parameter e
**********************************************************************/
int file_error(int e, char *filename)
{
static char *msgs[] = {
"Error in closing file %s",
"Sprite file is not complete",
"Cannot find file %s",
""
};
message(msgs[3+e], filename);
return e;
}
/**********************************************************************
* Inverts the givent sprite's active bitmap
**********************************************************************/
void invert(SPRED_DATA *sdp)
{
int i,j;
for(i=0; i<sdp->w; i++)
for(j=0; j<sdp->h; j++)
if (sdp->maps[sdp->map][i][j] == DOT_FOREGROUND)
sdp->maps[sdp->map][i][j] = DOT_BACKGROUND;
else
sdp->maps[sdp->map][i][j] = DOT_FOREGROUND;
}
/**********************************************************************
* Rotate the given sprites active bitmap 90 degrees anticlockwise
**********************************************************************/
void rotate_90(SPRED_DATA *sdp)
{
int i,j, lim, tmp;
if (sdp->w > sdp->h)
lim = sdp->h-1;
else
lim = sdp->w-1;
for(i=0; i<(lim+1)/2; i++)
for(j=0; j<(lim+1)/2; j++) {
tmp = sdp->maps[sdp->map][i][j];
sdp->maps[sdp->map][i][j]
= sdp->maps[sdp->map][lim - j][i];
sdp->maps[sdp->map][lim - j][i]
= sdp->maps[sdp->map][lim - i][lim - j];
sdp->maps[sdp->map][lim - i][lim - j]
= sdp->maps[sdp->map][j][lim - i];
sdp->maps[sdp->map][j][lim - i]
= tmp;
}
}
/**********************************************************************
* Rotate the active map 'angle' degrees anticlockwise.
* The transformation is done in reverse order, ie the points in the
* destination bitmap are projected into the source bitmap. This
* usually produces better rotations.
* NOTE: uses the global temp_map
**********************************************************************/
void rotate(SPRED_DATA *sdp, double angle)
{
int i,j, i1,j1;
double s,c,xo,yo;
angle = M_PI*angle/180;
s = sin(angle);
c = cos(angle);
xo = (sdp->w - 1)/2.0;
yo = (sdp->h - 1)/2.0;
for(i=0; i < sdp->w; i++)
for(j=0; j < sdp->h; j++) {
i1 = (c*(i - xo) - s*(j - yo)) + xo;
j1 = (s*(i - xo) + c*(j - yo)) + yo;
if (i1>=0 && i1<sdp->w && j1>=0 && j1<sdp->h)
temp_map[i][j] = sdp->maps[sdp->map][i1][j1];
else
temp_map[i][j] = DOT_BACKGROUND;
}
memcpy(sdp->maps[sdp->map], temp_map, sizeof(temp_map));
}
/**********************************************************************
* Make part of the given sprite's active map fatter.
* If a point's color is 'mid' and it has a neighbour which is in color
* 'border', then the point's color is changed to 'border'.
* NOTE: uses the global temp_map
**********************************************************************/
void make_fatter(SPRED_DATA *sdp, int mid, int border)
{
int i,j;
for(i=0; i < sdp->w; i++)
for(j=0; j < sdp->h; j++) {
if ( sdp->maps[sdp->map][i][j]==mid
&& ( (i > 0 && sdp->maps[sdp->map][i-1][j]==border)
||(j > 0 && sdp->maps[sdp->map][i][j-1]==border)
||(i < sdp->w-1 && sdp->maps[sdp->map][i+1][j]==border)
||(j < sdp->h-1 && sdp->maps[sdp->map][i][j+1]==border)))
temp_map[i][j] = border;
else
temp_map[i][j] = sdp->maps[sdp->map][i][j];
}
memcpy(sdp->maps[sdp->map], temp_map, sizeof(temp_map));
}
/**********************************************************************
* Load the sprite from the given file. If filename is a null string,
* then the sdp->name is used.
**********************************************************************/
void load(SPRED_DATA *sdp, char *filename)
{
sdp->w = width;
sdp->h = height;
if (filename[0]!='\0')
strcpy(sdp->name, filename);
if (strrchr(sdp->name, '.')==NULL)
strcat(sdp->name, FILE_EXTENSION);
message("Loading %s", sdp->name);
if (file_error(load_sprite(sdp), sdp->name)==0)
message("File: %s Size: %dx%d", sdp->name, sdp->w, sdp->h);
else if ((sdp->w | sdp->h) == 0) {
sdp->w = 32;
sdp->h = 24;
}
draw_screen(sdp);
}
/**********************************************************************
* Edit the given sprite. The screen must be in graphics mode and
* the mouse interface must be functional.
*
* Return: 0 if normal exit with save, negative if quit
**********************************************************************/
int spred_edit(SPRED_DATA *sdp, int filec, char **filev)
{
char buf[SPR_NAME_LEN];
MSG msg;
int x,y, ox, oy, i,j, tmp, quit, curfile;
static double angle = 30.0;
sdp->map = SPR_SHAPE;
curfile = 0;
load(sdp, filev[curfile]);
quit = FALSE;
ox = oy = -1;
while (!quit) {
msg=get_msg(sdp, &x,&y);
switch (msg) {
case MSG_QUIT:
quit = TRUE;
break;
case MSG_EXIT:
if (file_error(save_sprite(sdp), sdp->name)==0)
quit = TRUE;
break;
case MSG_SAVE:
message("Give the save filename [%s]:", sdp->name);
if (gr_gets(buf, SPR_NAME_LEN)!=NULL) {
if (buf[0]!='\0')
strcpy(sdp->name, buf);
if (strrchr(sdp->name, '.')==NULL)
strcat(sdp->name, FILE_EXTENSION);
message("Saving %s", sdp->name);
file_error(save_sprite(sdp), sdp->name);
}
else
message("");
break;
case MSG_LOAD:
message("Give the load filename [%s]:", sdp->name);
if (gr_gets(buf, SPR_NAME_LEN)!=NULL)
load(sdp, buf);
else
message("");
break;
case MSG_NEXT:
if (curfile+1 < filec)
load(sdp, filev[++curfile]);
else
message("No more sprites");
break;
case MSG_PREV:
if (curfile > 0)
load(sdp, filev[--curfile]);
else
message("No previous sprites");
break;
case MSG_CLEAR:
memset(sdp->maps[sdp->map], DOT_BACKGROUND,sizeof(SPRED_MAP));
draw_map(sdp, sdp->map);
break;
case MSG_COPY_TO_SHAPE:
memcpy(sdp->maps[SPR_SHAPE], sdp->maps[SPR_MASK],
sizeof(sdp->maps[sdp->map]));
sdp->map = SPR_SHAPE;
invert(sdp);
draw_map(sdp, SPR_SHAPE);
break;
case MSG_COPY_TO_MASK:
memcpy(sdp->maps[SPR_MASK], sdp->maps[SPR_SHAPE],
sizeof(sdp->maps[sdp->map]));
sdp->map = SPR_MASK;
invert(sdp);
draw_map(sdp, SPR_MASK);
break;
case MSG_ACTIVATE_MASK:
sdp->map = SPR_MASK;
draw_map(sdp, sdp->map);
break;
case MSG_ACTIVATE_SHAPE:
sdp->map = SPR_SHAPE;
draw_map(sdp, sdp->map);
break;
/***** Point drawing functions *****/
case MSG_BTN1_CLICK: /** set point **/
sdp->maps[sdp->map][x][y] = DOT_FOREGROUND;
draw_point(sdp, x, y, sdp->map);
message("Last point: X=%d Y=%d", x,y);
break;
case MSG_BTN2_CLICK: /** flip point **/
if (x!=ox || y!=oy) {
if (sdp->maps[sdp->map][x][y] == DOT_FOREGROUND)
sdp->maps[sdp->map][x][y] = DOT_BACKGROUND;
else
sdp->maps[sdp->map][x][y] = DOT_FOREGROUND;
draw_point(sdp, x, y, sdp->map);
}
message("Last point: X=%d Y=%d", x,y);
break;
case MSG_BTN3_CLICK: /** clear point **/
sdp->maps[sdp->map][x][y] = DOT_BACKGROUND;
draw_point(sdp, x, y, sdp->map);
message("Last point: X=%d Y=%d", x,y);
break;
/***** Image manipulation commands *****/
case MSG_INVERT:
invert(sdp);
draw_map(sdp, sdp->map);
break;
case MSG_OVERLAY:
draw_map(sdp, sdp->map | DOT_OVERLAY);
break;
case MSG_ROTATE90:
rotate_90(sdp);
draw_map(sdp, sdp->map);
break;
case MSG_ROTATE:
message("Give rotation angle [%.1lf]:", angle);
if (gr_gets(buf, sizeof(buf))!=NULL) {
if (buf[0]!='\0')
angle = atof(buf);
rotate(sdp, angle);
draw_map(sdp, sdp->map);
}
message("");
break;
case MSG_HFLIP:
for(i=0; i<sdp->w/2; i++)
for(j=0; j<sdp->h; j++) {
tmp = sdp->maps[sdp->map][sdp->w - i - 1][j];
sdp->maps[sdp->map][sdp->w - i - 1][j]
= sdp->maps[sdp->map][i][j];
sdp->maps[sdp->map][i][j] = tmp;
}
draw_map(sdp, sdp->map);
break;
case MSG_VFLIP:
for(i=0; i<sdp->w; i++)
for(j=0; j<sdp->h/2; j++) {
tmp = sdp->maps[sdp->map][i][sdp->h - j - 1];
sdp->maps[sdp->map][i][sdp->h - j - 1]
= sdp->maps[sdp->map][i][j];
sdp->maps[sdp->map][i][j] = tmp;
}
draw_map(sdp, sdp->map);
break;
case MSG_HMIRROR:
for(i=0; i<sdp->w/2; i++)
for(j=0; j<sdp->h; j++) {
tmp = sdp->maps[sdp->map][sdp->w - i - 1][j];
if (sdp->maps[sdp->map][i][j]==DOT_FOREGROUND)
sdp->maps[sdp->map][sdp->w - i - 1][j]
= sdp->maps[sdp->map][i][j];
if (tmp==DOT_FOREGROUND)
sdp->maps[sdp->map][i][j] = tmp;
}
draw_map(sdp, sdp->map);
break;
case MSG_VMIRROR:
for(i=0; i<sdp->w; i++)
for(j=0; j<sdp->h/2; j++) {
tmp = sdp->maps[sdp->map][i][sdp->h - j - 1];
if (sdp->maps[sdp->map][i][j]==DOT_FOREGROUND)
sdp->maps[sdp->map][i][sdp->h - j - 1]
= sdp->maps[sdp->map][i][j];
if (tmp==DOT_FOREGROUND)
sdp->maps[sdp->map][i][j] = tmp;
}
draw_map(sdp, sdp->map);
break;
case MSG_FATTER:
make_fatter(sdp, DOT_BACKGROUND, DOT_FOREGROUND);
draw_map(sdp, sdp->map);
break;
case MSG_THINNER:
make_fatter(sdp, DOT_FOREGROUND, DOT_BACKGROUND);
draw_map(sdp, sdp->map);
break;
case MSG_NONE:
break;
default:
message("Message %d not implemented", msg, x, y);
}
ox = x;
oy = y;
}
return -(msg == MSG_QUIT);
}
/**********************************************************************
* The sprite to be edited. Must be global, since the structure
* take about 20 kBytes. It is automatically initialized to zero.
**********************************************************************/
SPRED_DATA sd;
void main(int argc, char **argv)
{
int i,j;
puts("SPRED -- Sprite editor v1.1 -- Copyright (C) 1991 Jari Karjala");
if (argc<2 || (argc==2 && argv[1][0]=='-'))
error("\nUSAGE: SPRED [-WxH] sprite[.ext] [...]\n");
/** get size if given **/
if (argc>2 && argv[1][0]=='-') {
if (sscanf(&argv[1][1], "%dx%d", &width, &height)!=2)
error("Illegal width/height format, use WxH, eg 32x24");
if (width > MAX_SPRITE_WIDTH || height > MAX_SPRITE_HEIGHT)
error("Sprite too large, max size %dx%d",
MAX_SPRITE_WIDTH, MAX_SPRITE_HEIGHT);
argc--;
argv++;
}
gr_detect(GR_TYPE_SPR, &i, &j);
if (i == -1) {
puts("Unsupported graphics mode, sorry!");
exit(1);
}
gr_start(&i, &j);
if (mouse_initialize()==0)
error("No mouse driver found, cannot continue");
mouse_set_pointer_xy(gr_max_x/2, 3*gr_max_y/4);
if (spred_edit(&sd, argc-1, argv+1) < 0)
exit(1); /** some error, or quit **/
exit(0);
}